home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 19 / Mac Magazin and MacEasy Magazine CD - Issue 19.iso / Utilities / uae-0.4 / Source Code / disk.c < prev    next >
Text File  |  1996-02-05  |  10KB  |  448 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * Floppy disk emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt, Hannu Rummukainen
  7.   */
  8.  
  9. #include <string.h>
  10. #include <stdio.h>
  11.  
  12. #include "config.h"
  13. #include "amiga.h"
  14. #include "options.h"
  15. #include "memory.h"
  16. #include "ersatz.h"
  17. #include "disk.h"
  18.  
  19. int indexpulse = 0;
  20.  
  21. UWORD* mfmwrite;
  22. static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */
  23.  
  24. static int side, direction, step;
  25. static UBYTE selected = 15;
  26. static bool dskready;
  27. static bool need_read = false;
  28.  
  29. typedef struct {
  30.     UWORD sync;
  31.     UWORD len;
  32.     ULONG offs;
  33. } trackid;
  34.  
  35. typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype;
  36. typedef struct {
  37.     FILE *diskfile;
  38.     drive_filetype filetype;
  39.     trackid trackdata[164];
  40.     unsigned int track;
  41.     bool motoroff;
  42.     bool wrprot;
  43.     unsigned int trackoffs,insecpos;
  44.     bool secok;
  45.     UBYTE secbuf[544];
  46.     UWORD mfmbuf[544];
  47. } drive;
  48.  
  49. drive floppy[4];
  50.  
  51. static void drive_insert(drive *drv, char *fname)
  52. {
  53.     unsigned char buffer[10];
  54.     
  55.     drv->diskfile = fopen(fname,"r+b");
  56.     if (drv->diskfile) {
  57.     drv->wrprot = false;
  58.     } else {
  59.     drv->wrprot = true;
  60.     drv->diskfile = fopen(fname, "rb");
  61.     if (!drv->diskfile) return;
  62.     }
  63.     fread(buffer,sizeof(char),8,drv->diskfile);
  64.     if (strncmp((char *)buffer,"UAE--ADF",8) == 0) {    
  65.     int offs = 160*4+8;
  66.     int i;
  67.     
  68.         drv->filetype = ADF_EXT1;
  69.     drv->wrprot = true; /* write to adf_ext1 not implemented */
  70.     for(i=0; i<160; i++) {
  71.         fread(buffer, 4, 1, drv->diskfile);
  72.         drv->trackdata[i].sync = buffer[0]*256 + buffer[1];
  73.         drv->trackdata[i].len = buffer[2]*256 + buffer[3];
  74.         drv->trackdata[i].offs = offs;
  75.         offs += drv->trackdata[i].len;
  76.     }
  77.     } else {
  78.     int i;
  79.         drv->filetype = ADF_NORMAL;
  80.     for(i=0; i<160; i++) {
  81.         drv->trackdata[i].len = 512 * 11;
  82.         drv->trackdata[i].sync = 0;
  83.         drv->trackdata[i].offs = i*512*11;
  84.     }
  85.     }
  86. }
  87.  
  88.  
  89. static void drive_step(drive *drv)
  90. {
  91.     if (direction) {
  92.     if (drv->track) drv->track--;
  93.     } else {
  94.     if (drv->track < 85) drv->track++;
  95.     }
  96. }
  97.  
  98.  
  99. static bool drive_track0(drive *drv) 
  100. {
  101.     return drv->track == 0; 
  102. }
  103.  
  104. static bool drive_writeprotected(drive *drv) 
  105. {
  106.     return drv->wrprot || drv->diskfile == NULL; 
  107. }
  108.  
  109. static bool drive_empty(drive *drv)
  110. {
  111.     return drv->diskfile == 0; 
  112. }
  113.  
  114. static bool drive_running(drive *drv)
  115. {
  116.     return !drv->motoroff; 
  117. }
  118.  
  119. static void drive_index(drive *drv)
  120. {
  121.     drv->trackoffs = 0;
  122.     drv->insecpos = 0;
  123. }
  124.  
  125. static void drive_motor(drive *drv, bool off)
  126. {
  127.     if (drv->motoroff && !off) { 
  128.     drv->trackoffs = 0;
  129.     drv->insecpos = 0; 
  130.     drv->secok = false; 
  131.     }
  132.     drv->motoroff = off;
  133. }
  134.  
  135. static ULONG drive_getmfmulong(drive *drv, unsigned int offs)
  136. {
  137.     return (drv->mfmbuf[offs] << 16) | drv->mfmbuf[offs+1];
  138. }
  139.  
  140. static ULONG drive_getseculong(drive *drv, unsigned int offs)
  141. {
  142.     return ((drv->secbuf[offs] << 24) | (drv->secbuf[offs+1] << 16) 
  143.         | (drv->secbuf[offs+2] << 8) | (drv->secbuf[offs+3]));
  144. }
  145.  
  146. static void drive_readsec(drive *drv)
  147. {
  148.     ULONG deven,dodd;
  149.     ULONG hck=0,dck=0;
  150.     int i;
  151.  
  152.     if (!drv->diskfile) return;
  153.     
  154.     drv->secbuf[0] = drv->secbuf[1] = 0x00;
  155.     drv->secbuf[2] = drv->secbuf[3] = 0xa1;
  156.     drv->secbuf[4] = 0xff;
  157.     drv->secbuf[5] = drv->track*2 + side;
  158.     drv->secbuf[6] = drv->trackoffs;
  159.     drv->secbuf[7] = 11-drv->trackoffs;
  160.     
  161.     for(i = 8; i < 24; i++)
  162.     drv->secbuf[i] = 0;
  163.     
  164.     fseek(drv->diskfile, 
  165.       drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512, 
  166.       SEEK_SET);
  167.     fread(&drv->secbuf[32],sizeof(UBYTE),512,drv->diskfile);
  168.     
  169.     drv->mfmbuf[0] = drv->mfmbuf[1] = 0xaaaa;
  170.     drv->mfmbuf[2] = drv->mfmbuf[3] = 0x4489;
  171.     
  172.     deven = drive_getseculong(drv, 4); dodd = deven >> 1;
  173.     deven &= 0x55555555; dodd &= 0x55555555;
  174.     
  175.     drv->mfmbuf[4] = dodd >> 16;
  176.     drv->mfmbuf[5] = dodd;
  177.     drv->mfmbuf[6] = deven>> 16; 
  178.     drv->mfmbuf[7] = deven;
  179.     
  180.     for (i = 8; i < 48; i++)
  181.     drv->mfmbuf[i] = 0;
  182.     for (i = 0; i < 512; i += 4){
  183.     deven = drive_getseculong(drv, i + 32);
  184.     dodd = deven >> 1;
  185.     deven &= 0x55555555; dodd &= 0x55555555;
  186.     drv->mfmbuf[(i>>1)+32] = dodd >> 16;
  187.     drv->mfmbuf[(i>>1)+33] = dodd;
  188.     drv->mfmbuf[(i>>1)+256+32] = deven>> 16;
  189.     drv->mfmbuf[(i>>1)+256+33] = deven;
  190.     }
  191.     
  192.     for(i = 4; i < 24; i += 2)
  193.     hck ^= drive_getmfmulong(drv, i);
  194.     
  195.     deven = dodd = hck; dodd >>= 1;
  196.     drv->mfmbuf[24] = dodd >> 16; drv->mfmbuf[25] = dodd;
  197.     drv->mfmbuf[26] = deven>> 16; drv->mfmbuf[27] = deven;
  198.     
  199.     for(i = 32; i < 544; i += 2)
  200.     dck ^= drive_getmfmulong(drv, i);
  201.     
  202.     deven = dodd = dck; dodd >>= 1;
  203.     drv->mfmbuf[28] = dodd >> 16; drv->mfmbuf[29] = dodd;
  204.     drv->mfmbuf[30] = deven>> 16; drv->mfmbuf[31] = deven;
  205.     
  206.     drv->secok = true;
  207.     need_read = false;
  208.     drv->insecpos = 0;
  209. }
  210.  
  211. static void drive_get_data(drive *drv, UWORD *mfm, UWORD *byt)
  212. {
  213.     if (drv->trackdata[drv->track*2 + side].sync == 0) {
  214.     /* Normal AmigaDOS format track */
  215.     if (!drv->secok || need_read)
  216.         drive_readsec(drv);
  217.     *mfm = drv->mfmbuf[drv->insecpos]; 
  218.     *byt = drv->secbuf[drv->insecpos++];
  219.     
  220.     if (drv->insecpos == 544){
  221.         drv->insecpos = 0;
  222.         drv->secok = false;
  223.         if (++drv->trackoffs == 11)
  224.         drv->trackoffs = 0;
  225.     }
  226.     } else {
  227.     /* Raw MFM track */
  228.     if (drv->insecpos > drv->trackdata[drv->track*2+side].len) 
  229.         drv->insecpos = 0;
  230.     if (drv->insecpos == 0) {
  231.         *mfm = drv->trackdata[drv->track*2 + side].sync;
  232.     } else  {        
  233.         unsigned char data[2];
  234.         fseek(drv->diskfile, 
  235.           drv->insecpos*2 - 2 + drv->trackdata[drv->track*2+side].offs, 
  236.           SEEK_SET);
  237.         fread(data, 2, 1, drv->diskfile);
  238.         *mfm = data[0]*256 + data[1];
  239.         /* ??? how does this work? */
  240.         *byt = (data[0] & 0x55) | ((data[1] & 0x55)*2);
  241.     }
  242.     drv->insecpos++;
  243.     }
  244. }
  245.  
  246. #define MFMMASK 0x55555555
  247. static __inline__ ULONG getmfmlong(UWORD* mbuf) 
  248. {
  249.     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
  250. }
  251.  
  252. static void drive_write_data(drive *drv, UWORD *mbuf, UWORD *mend)
  253. {
  254.     int i, secwritten = 0;
  255.     ULONG odd, even, chksum, id, dlong;
  256.     UBYTE* secdata;
  257.     
  258.     if (drive_writeprotected(drv)) return;
  259.     mend -= (4 + 16 + 8 + 512);
  260.     while (mbuf < mend) {
  261.     do {
  262.         while (*mbuf++ != 0x4489) {
  263.         if (mbuf >= mend) return;
  264.         }
  265.     } while (*mbuf++ != 0x4489);
  266.     
  267.     odd = getmfmlong(mbuf);
  268.     even = getmfmlong(mbuf+2);
  269.     mbuf += 4;    
  270.     id = (odd << 1) | even;
  271.     
  272.     drv->trackoffs = (id & 0xff00) >> 8;
  273.     if (drv->trackoffs > 10) {
  274.         printf("Disk write: weird sector number %d\n", drv->trackoffs);
  275.         continue;
  276.     }
  277.     chksum = odd ^ even;
  278.     for (i=0; i<4; i++) {
  279.         odd = getmfmlong(mbuf);
  280.         even = getmfmlong(mbuf+8);
  281.         mbuf += 2;
  282.         
  283.         dlong = (odd << 1) | even;
  284.         if (dlong)  secwritten = -200;
  285.         chksum ^= odd ^ even;
  286.     }  /* could check here if the label is nonstandard */
  287.     mbuf += 8;
  288.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  289.     if ((((odd << 1) | even) != chksum) || 
  290.         (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) {
  291.         printf("Disk write: checksum error on sector header\n");
  292.         continue;
  293.     }
  294.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  295.     chksum = (odd << 1) | even;
  296.     secdata = drv->secbuf + 32;
  297.     for (i=0; i<128; i++) {
  298.         odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2;
  299.         dlong = (odd << 1) | even;
  300.         *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff;
  301.         *secdata++ = dlong >> 8; *secdata++ = dlong;
  302.         chksum ^= odd ^ even;
  303.     }
  304.     mbuf += 256;
  305.     if (chksum) {
  306.         printf("Disk write: data checksum error\n");
  307.         continue;
  308.     }
  309.     secwritten++;
  310.     fseek(drv->diskfile, 
  311.           drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512,
  312.           SEEK_SET);
  313.     fwrite(drv->secbuf+32, sizeof(UBYTE), 512, drv->diskfile);
  314.     }
  315.     if (++drv->trackoffs == 11) drv->trackoffs = 0;
  316.     drv->insecpos = 0;
  317.     drv->secok = false;
  318.     
  319.     if (secwritten == 0) 
  320.     printf("Disk write in unsupported format\n");
  321.     if (secwritten < 0)
  322.     printf("Disk write: sector labels ignored\n");
  323. }
  324.  
  325. static void drive_init(drive *drv, char *fname)
  326. {
  327.     drv->diskfile = 0;
  328.     if (fname != 0) drive_insert(drv, fname);
  329.     drv->track = 0;
  330.     drv->motoroff = true;
  331. }
  332.  
  333. static void drive_eject(drive *drv)
  334. {
  335.     if (!drive_empty(drv)) fclose(drv->diskfile);
  336.     drv->diskfile = 0;
  337. }
  338.  
  339. /* We use this function if we have no Kickstart ROM. */
  340. void DISK_ersatz_read (int tr, int sec, CPTR dest)
  341. {
  342.     int i;
  343.  
  344.     floppy[0].trackoffs = sec;
  345.     floppy[0].insecpos = 0;
  346.     
  347.     side = tr & 1;
  348.     floppy[0].track = tr >> 1;
  349.     drive_readsec(floppy);
  350.     for (i = 0; i < 512; i++) {
  351.     put_byte (dest + i, floppy[0].secbuf[32+i]);
  352.     }
  353.     
  354. }
  355.  
  356. void DISK_init()
  357. {
  358.     drive_insert(floppy, "df0.adf");
  359.     drive_insert(floppy + 1, "df1.adf");
  360.     drive_insert(floppy + 2, "df2.adf");
  361.     drive_insert(floppy + 3, "df3.adf");
  362. }
  363.  
  364. void DISK_Index()
  365. {
  366.     int i;
  367.     for(i=0; i<4; i++) {    
  368.     drive_index(floppy + i);
  369.     }
  370. }
  371.  
  372. void DISK_select(UBYTE data)
  373. {
  374.     int step_pulse;
  375.     int dr;
  376.     
  377.     if (selected != ((data >> 3) & 15)) dskready = false;
  378.     selected = (data >> 3) & 15;
  379.     if (side != 1 - ((data >> 2) & 1)) {
  380.     side = 1 - ((data >> 2) & 1);
  381.     need_read = true;
  382.     }
  383.     direction = (data >> 1) & 1;
  384.     step_pulse = data & 1;
  385.     if (step != step_pulse) {
  386.     step = step_pulse;
  387.     if (step == 0){
  388.         for (dr = 0; dr < 4; dr++){
  389.         if (!(selected & (1 << dr))) {
  390.             drive_step(floppy + dr);
  391.         }
  392.         }
  393.     }
  394.     }
  395.     for (dr = 0; dr < 4; dr++){
  396.     if (!(selected & (1<<dr))) {
  397.         drive_motor(floppy + dr, data >> 7);
  398.     }
  399.     }
  400. }
  401.  
  402. UBYTE DISK_status()
  403. {
  404.     UBYTE st = 0x3c;
  405.     int dr;
  406.     
  407.     for (dr = 0; dr < 4; dr++){
  408.     if (!(selected & (1 << dr))) {
  409.         if (drive_running(floppy + dr)){
  410.         if (dskready) st &= ~0x20;
  411.         dskready = true;
  412.         } else {
  413.         st &= ~0x20; /* report drive ID */
  414.         }
  415.         
  416.         if (drive_track0(floppy + dr)) { st &= ~0x10; }
  417.         if (drive_writeprotected(floppy + dr)) { st &= ~8; }
  418.         if (drive_empty(floppy + dr)) { st &= ~0x4; }
  419.     }
  420.     }
  421.     return st;
  422. }
  423.  
  424. void DISK_GetData(UWORD *mfm,UWORD *byt)
  425. {
  426.     int dr;
  427.     for (dr = 0; dr < 4; dr++){
  428.     if (!(selected & (1<<dr))) {
  429.         drive_get_data (floppy + dr, mfm, byt);
  430.     }
  431.     }
  432. }
  433.  
  434. void DISK_InitWrite()
  435. {
  436.     mfmwrite = mfmwrbuffer;
  437. }
  438.  
  439. void DISK_WriteData()
  440. {
  441.     int dr;
  442.     for (dr=0;dr<4;dr++){
  443.     if (!(selected & (1<<dr))) {
  444.         drive_write_data(floppy + dr, mfmwrbuffer, mfmwrite);
  445.     }
  446.     }
  447. }
  448.